using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Client;
using System.Runtime.Remoting.Messaging;
using UKVSTS;

namespace IEeee
{
    /// <summary>
    /// Simple form to allow the user to input some data and to configure what is
    /// included in our bug report.
    /// </summary>
    public partial class BugDescription : Form
    {
        private String m_ImageFileName;

        ImageFormat m_SaveChangeImageAs;
        
        public BugDescription()
        {
            InitializeComponent ();
        }

        public void SetScreenshotDetails(String imagefileName, ImageFormat saveChangeImageAs)
        {
            ArgTest.IsNotNullOrEmpty(imagefileName, "imagefileName");
            ArgTest.IsNotNull(saveChangeImageAs, "saveChangeImageAs");

            m_ImageFileName = imagefileName;
            m_SaveChangeImageAs = saveChangeImageAs;

            cmdEditImage.Enabled = true ;
        }

        private void BugDescription_Load (object sender, EventArgs e)
        {
            // This fixes an allignment problem with these chack boxes.
            // I'm sure i've done something wrong, but this is a quick simple
            // fix to allow me to get on with other things.
            //
            // TODO: Fix this properly.
            //
            chkScriptFiles.Left = chkStyleSheets.Left;
            chkDescription.Left = chkStyleSheets.Left;

            chkScreenShot.Checked = IEeeeConfig.Instance.IncludeScreenShot;
            chkSourceFile.Checked = IEeeeConfig.Instance.IncludeSourceHtml;
            chkScriptFiles.Checked = IEeeeConfig.Instance.IncludeScriptFiles;
            chkStyleSheets.Checked = IEeeeConfig.Instance.IncludeStyleSheets;
            chkDescription.Checked = IEeeeConfig.Instance.IncludeBrowserDetails;
            chkFrames.Checked = IEeeeConfig.Instance.IncludeFramesAndIFrames;
            chkFieldDefaultValues.Checked = IEeeeConfig.Instance.ApplyDefaultValues;
        }

        /// <summary>
        /// The Title that the user has entered for this bug.
        /// </summary>
        public String BugTitle
        {
            get { return txtTitle.Text; }
            set { txtTitle.Text = value; }
        }

        /// <summary>
        /// The Details that the user has entered for this bug.
        /// </summary>
        public String BugDetails
        {
            get { return txtDescription.Text; }
        }

        /// <summary>
        /// Whether the user wants to include the screenshot in the bug report.
        /// </summary>
        public bool InculdeScreenShot
        {
            get { return chkScreenShot.Checked; }
        }

        /// <summary>
        /// Whether the user wants to include the source for the main page in the bug report.
        /// </summary>
        public bool InculdeMainSourceFile
        {
            get { return chkSourceFile.Checked; }
        }

        /// <summary>
        /// Whether the user wants to include any script source files in the bug report.
        /// </summary>
        public bool InculdeScriptFiles
        {
            get { return chkScriptFiles.Checked; }
        }

        /// <summary>
        /// Whether the user wants to include any style sheet source files in the bug report.
        /// </summary>
        public bool InculdeStyleSheets
        {
            get { return chkStyleSheets.Checked; }
        }

        /// <summary>
        /// Whether the user wants to include the browser details in the bug report.
        /// </summary>
        public bool InculdeBrowserDetails
        {
            get { return chkDescription.Checked; }
        }

        /// <summary>
        /// Whether the user wants to include any frame of iframe source files in the bug report.
        /// </summary>
        public bool InculdeFrames
        {
            get { return chkFrames.Checked; }
        }

        public bool ApplyFieldDefaultValues
        {
            get { return chkFieldDefaultValues.Checked; }
        }

        public String WorkItemFieldName
        {
            get { return cmbWorkItemFieldName.SelectedItem.ToString(); }
        }

        /// <summary>
        /// Allows the user to change the server / project that this work item
        /// will be written to.
        /// </summary>
        private void cmdChange_Click (object sender, EventArgs e)
        {
            try
            {
                using (ServerConfigForm configDialog = new ServerConfigForm ())
                {
                    if (configDialog.ShowDialog() == DialogResult.OK)
                    {
                        if (IEeeeConfig.Instance.IsConnectedToSelectedTFS)
                        {
                            SuccessfulConnection();
                        }
                        else
                        {
                            UnsuccessfulConnection("No server selected");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                IEeeeException.DisplayError (this, ex);
            }
        }

        /// <summary>
        /// Stops the annimation, makes it hidden and displays the
        /// change connection button.
        /// </summary>
        private void StopConnectionAnimation()
        {
            if (picStatusAnimation != null)
            {
                picStatusAnimation.Visible = false;
                Controls.Remove(picStatusAnimation);
//                picStatusAnimation.Dispose();
//                picStatusAnimation = null;
            }

            cmdChange.Visible = true;
        }

        /// <summary>
        /// Ensures that the user configures the server before we allow then to
        /// start creating the work item.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BugDescription_Shown(object sender, EventArgs e)
        {
            if (IEeeeConfig.Instance.HasEnoughInfoToConnect == false)
            {
                // Show the server selection dialog.
                //
                cmdChange_Click(sender, e);
            }
            else
            {
                StartConnectionToSelectedServer();
            }
        }

        /// <summary>
        /// Starts an Async call to connect to the selected TFS.
        /// </summary>
        private void StartConnectionToSelectedServer()
        {
            try
            {
                lblServerDetails.Text = String.Format("Connecting to {0} ...",
                                                      IEeeeConfig.Instance.ServerName);

                // Stop anyone from changing the config while we
                // are background loading it.
                //
                cmdChange.Visible = false;
                picStatusAnimation.Visible = true;

                // Make an async connection to the server.
                //
                AsyncCallback callback = new AsyncCallback(ConnectToTFSCallback);
                IEeeeConfig.Instance.BeginConnectToSelectedTFS(new UICredentialsProvider(), callback);
            }
            catch (Exception ex)
            {
                IEeeeException.DisplayError(this, ex);
            }
        }

        private delegate void StringMethodInvoker (String arg);

        /// <summary>
        /// This function is called when the async call to connect to the TFS
        /// completes.
        /// </summary>
        /// <param name="result"></param>
        private void ConnectToTFSCallback(IAsyncResult result)
        {
            try
            {
                // This will get our return value or throw an exception that
                // occured during the connection.
                //
                bool connected = IEeeeConfig.Instance.EndConnectToSelectedTFS(result);

                if (connected)
                {
                    // We are not running on the UI thread, so we need to do
                    // an invoke to get on the UI thread.
                    //
                    Invoke ( new MethodInvoker (SuccessfulConnection));
                } else {
                    // We are not running on the UI thread, so we need to do
                    // an invoke to get on the UI thread.
                    //
                    Invoke(new StringMethodInvoker(UnsuccessfulConnection), "");
                }
            }
            catch (Exception ex)
            {
                // We are not running on the UI thread, so we need to do
                // an invoke to get on the UI thread.
                //
                Invoke(new IEeeeException.DisplayErrorInvoker (IEeeeException.DisplayError), this, ex);
                Invoke(new StringMethodInvoker(UnsuccessfulConnection), ex.Message);
            }
        }

        /// <summary>
        /// Called to indicate that we are successfully connected to TFS.
        /// Enable the OK button and marks up the rest of the UI to continue
        /// creating a bug.
        /// </summary>
        private void SuccessfulConnection()
        {
            StopConnectionAnimation();

            lblServerDetails.Text  = String.Format("This will create a {0} in the {1} project on {2}.",
                                        IEeeeConfig.Instance.SelectedWorkItemType.Name,
                                        IEeeeConfig.Instance.SelectedProject.Name,
                                        IEeeeConfig.Instance.SelectedServer.Name);

            // Populate the list of possible filed that the browser description can
            // be entered. This is to allow the browser details to be stored in a field
            // other than the CoreFields.Description field
            //
            cmbWorkItemFieldName.Items.Clear();

            foreach (FieldDefinition fd in IEeeeConfig.Instance.SelectedWorkItemType.FieldDefinitions)
            {
                if (IEeeeButton.IsFieldSutableToStoreDescription(fd))
                {
                    cmbWorkItemFieldName.Items.Add(fd.Name);
                }
            }

            int descIndex = cmbWorkItemFieldName.Items.IndexOf(IEeeeConfig.Instance.SelectedWorkItemType.FieldDefinitions[CoreField.Description].Name);


            cmbWorkItemFieldName.SelectedIndex = Math.Max(descIndex, 0);

            cmbWorkItemFieldName.Enabled = true;

            cmdChange.Visible = true;
            cmdChange.Enabled = true;
            cmdOk.Enabled = true;
            cmdEditFieldDefaultValues.Enabled = true;
        }

        /// <summary>
        /// Sets up the UI to show that we were unable to connect to the server
        /// </summary>
        /// <param name="message"></param>
        private void UnsuccessfulConnection (String message)
        {
            lblServerDetails.Text = "Unable to connect: " + message;

            StopConnectionAnimation();

            // Ensure that the user can choose another server.
            //
            cmdChange.Visible = true;
            cmdChange.Enabled = true;

            // Can't continue until we are connected.
            //
            cmdOk.Enabled = false;
        }

        private void BugDescription_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (DialogResult == DialogResult.OK)
            {
                // Update our config file with the users settings.
                //
                IEeeeConfig.Instance.IncludeScreenShot = chkScreenShot.Checked;
                IEeeeConfig.Instance.IncludeSourceHtml = chkSourceFile.Checked;
                IEeeeConfig.Instance.IncludeScriptFiles = chkScriptFiles.Checked;
                IEeeeConfig.Instance.IncludeStyleSheets = chkStyleSheets.Checked;
                IEeeeConfig.Instance.IncludeBrowserDetails = chkDescription.Checked;
                IEeeeConfig.Instance.IncludeFramesAndIFrames = chkFrames.Checked;
                IEeeeConfig.Instance.ApplyDefaultValues = chkFieldDefaultValues.Checked;
                IEeeeConfig.Instance.DescriptionFieldName = cmbWorkItemFieldName.SelectedItem.ToString();
                IEeeeConfig.Instance.Save ();
            }
            else if (DialogResult == DialogResult.Cancel)
            {
                DialogResult res = MessageBox.Show (this,
                                                    "This bug report has not yet been saved.\nDo you want to discard the changes?",
                                                    "Work Item",
                                                    MessageBoxButtons.OKCancel,
                                                    MessageBoxIcon.Exclamation,
                                                    MessageBoxDefaultButton.Button2);

                switch (res)
                {
                    case DialogResult.OK:
                        e.Cancel = false;
                        break;
                    case DialogResult.Cancel:
                        e.Cancel = true;
                        break;
                    default:
                        System.Diagnostics.Debug.Assert (false, "Unexpected DialogResult: " + res.ToString ());
                        break;
                }
            }

            // Panaranoid clean up code.
            // Not sure I need this, but at one time it looked like it solved a 
            // small resource leak. But I can't be bothered to remove it an retest :-(
            //
            if (picStatusAnimation != null) {
                picStatusAnimation.Visible = false;
                Controls.Remove (picStatusAnimation);
                picStatusAnimation.Dispose ();
                picStatusAnimation = null;
            }
        }

        private void cmdEditImage_Click(object sender, EventArgs e)
        {
            Image imageToSave = null;
            try
            {
                // We need to have disposed of this Image object before we
                // can try and save the edited image - otherwise the 
                // file will still be locked.
                //
                using (Image img = Image.FromFile(m_ImageFileName))
                {
                    using (ImageModifier dialog = new ImageModifier(img))
                    {
                        DialogResult res = dialog.ShowDialog(this);

                        if (res == DialogResult.OK && dialog.HasImagedChanged)
                        {
                            imageToSave = dialog.GetModifiedImage();
                        }
                    }
                }

                // Do we have an image to save?
                //
                if (imageToSave != null)
                {
                    if (File.Exists(m_ImageFileName))
                    {
                        File.Delete(m_ImageFileName);
                    }

                    imageToSave.Save(m_ImageFileName, m_SaveChangeImageAs);
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(this,
                                "An error occured while opening the screenshot image:\n  " + ex.Message,
                                "Error",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
            }
            finally
            {
                if (imageToSave != null)
                {
                    imageToSave.Dispose();
                }
            }
        }

        /// <summary>
        /// Start up IE and visit the codeplex site.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void linkLatestVersion_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.codeplex.com/UKVSTS/Release/ProjectReleases.aspx");
        }

        private void cmdEditFieldDefaultValues_Click(object sender, EventArgs e)
        {
            try
            {
                using (WiDefaultValues dialog = new WiDefaultValues())
                {
                    dialog.WorkItemType = IEeeeConfig.Instance.SelectedWorkItemType;

                    dialog.ShowDialog(this);

                }
            }
            catch (Exception ex)
            {
                IEeeeException.DisplayError (this, ex);
            }
        }

        private void BugDescription_HelpButtonClicked(object sender, CancelEventArgs e)
        {
            e.Cancel = true;
            System.Diagnostics.Process.Start("http://www.codeplex.com/UKVSTS/Wiki/View.aspx?title=Bug%20Description");
        }
    }
}